import 'package:crypto/crypto.dart';
import 'package:encrypt/encrypt.dart';
import 'dart:convert';
import 'package:convert/convert.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:pointycastle/asymmetric/api.dart';
import 'dart:async';

final RSAKeyParser parser = RSAKeyParser();

class PPCryptoHelper {

    // base64 加密
    static String base64EncodeWithString(String str) {
        if(str != null && str.isNotEmpty) {
            List<int> content = utf8.encode(str);
            var digest = base64Encode(content);
            return digest;
        }
        return "";
    }

    // base64 解密
    static String base64DecodeWithString(String str) {
        if(str != null && str.isNotEmpty) {
            var digest = String.fromCharCodes(base64Decode(str));
            return digest;
        }
        return "";
    }

    // md5 加密 --- string值
    static String stringMd5EncodeWithString(String str) {
        if(str != null && str.isNotEmpty) {
            List<int> content = new Utf8Encoder().convert(str);
            Digest digest = md5.convert(content);
            return digest.toString();
        }
        return "";
    }

    // md5 加密 --- hex值
    static List<int> hexMd5EncodeWithString(String str) {
        if(str != null && str.isNotEmpty) {
            List<int> content = new Utf8Encoder().convert(str);
            Digest digest = md5.convert(content);
            return digest.bytes;
        }
        return [];
    }

    // md5 解密
    static String md5DecodeWithString(String str) {
        if(str != null && str.isNotEmpty) {
            return '';
        }
        return "";
    }

   // DES加密 ---- ECB 模式 padding 默认是 'PKCS7'
    static String desEncryptByECBMode(String message, String keyStr, String ivStr) {
        if(message != null && message.isNotEmpty) {
            final Key key = Key.fromUtf8(keyStr);
            final AESMode mode = AESMode.ecb;
            final encrypter = Encrypter(AES(key, mode: mode));
            final IV iv = ivStr != null && ivStr.isNotEmpty ? IV.fromUtf8(ivStr) : null;
            final encrypted = encrypter.encrypt(message, iv: iv);
            return encrypted.base64;
        }
        return "";
    }

    // DES解密 ---- ECB 模式 padding 默认是 'PKCS7'
    static String desDecryptByECBMode(ciphertext, String keyStr, String ivStr) {
        if(ciphertext != null) {
            final Key key = Key.fromUtf8(keyStr);
            final AESMode mode = AESMode.ecb;
            final encrypter = Encrypter(AES(key, mode: mode));
            final IV iv = ivStr != null && ivStr.isNotEmpty ? IV.fromUtf8(ivStr) : null;
            final decrypted = encrypter.decrypt(ciphertext, iv: iv);
            return decrypted.toString();
        }
        return "";
    }

     // DES加密 ---- CBC 模式 padding 默认是 'PKCS7'
    static String desEncryptByCBCMode(String message, String keyStr, String ivStr) {
        if(message != null && message.isNotEmpty) {
            final Key key = Key.fromUtf8(keyStr);
            final AESMode mode = AESMode.cbc;
            final encrypter = Encrypter(AES(key, mode: mode));
            final IV iv = ivStr != null && ivStr.isNotEmpty ? IV.fromUtf8(ivStr) : null;
            final encrypted = encrypter.encrypt(message, iv: iv);
            return encrypted.base64;
        }
        return "";
    }

    // DES解密 ---- CBC 模式 padding 默认是 'PKCS7'
    static String desDecryptByCBCMode(ciphertext, String keyStr, String ivStr) {
        if(ciphertext != null) {
            final Key key = Key.fromUtf8(keyStr);
            final AESMode mode = AESMode.cbc;
            final encrypter = Encrypter(AES(key, mode: mode));
            final IV iv = ivStr != null && ivStr.isNotEmpty ? IV.fromUtf8(ivStr) : null;
            final decrypted = encrypter.decrypt(ciphertext, iv: iv);
            return decrypted.toString();
        }
        return "";
    }

    // RSA加密 
    static Future<String> rsaEncrypt(String content, String keyPath) async {
        String publicKeyString = await rootBundle.loadString(keyPath);
        RSAPublicKey publicKey = parser.parse(publicKeyString);
        final Encrypter encrypter = Encrypter(RSA(publicKey: publicKey));
        final String res = encrypter.encrypt(content).base64;
        return res; 
    }

    // RSA加密 
    static Future<String> rsaDecode(String decoded, String keyPath) async {
        String privateKeyString = await rootBundle.loadString(keyPath);
        final privateKey = parser.parse(privateKeyString);
        final encrypter = Encrypter(RSA(privateKey: privateKey));
        final String result = encrypter.decrypt(Encrypted.fromBase64(decoded));
        return result;
    }


    // AES加密 
    static String aesEncrypt(String msgStr, String keyStr, String ivStr) {
        if(msgStr == null || msgStr.isEmpty) {
            return null;
        } else if (keyStr == null || keyStr.isEmpty) {
            return null;
        } else if (ivStr == null || ivStr.isEmpty) {
            return null;
        }
        keyStr = keyStr.length > 32 ? keyStr.substring(0, 32) : keyStr; // 加密密钥要求是32位长字符串，不足按padding方式补充
        ivStr = ivStr.length > 16 ? ivStr.substring(0, 16) : ivStr; // iv初始化向量是16位长度字符串

        String result = PPCryptoHelper.desEncryptByECBMode(msgStr, keyStr, ivStr);
        return result;
    }

    // AES解密
    static String aesDecrypt(msgStr, String keyStr, String ivStr) {
        if(msgStr == null || msgStr.isEmpty) {
            return null;
        } else if (keyStr == null || keyStr.isEmpty) {
            return null;
        } else if (ivStr == null || ivStr.isEmpty) {
            return null;
        }
        keyStr = keyStr.length > 32 ? keyStr.substring(0, 32) : keyStr; // 加密密钥要求是32位长字符串，不足按padding方式补充
        ivStr = ivStr.length > 16 ? ivStr.substring(0, 16) : ivStr; // iv初始化向量是16位长度字符串

        String result = PPCryptoHelper.desDecryptByCBCMode(msgStr, keyStr, ivStr);
        return result;
    }


    // pbeWithMd5
    static pbeWithMd5AndDesEncrypt(String msgStr, String pwd, String salt, int iterationCount) {
        Map<String, String> keyAndivHexObj = PPCryptoHelper.getKeyHexAndIvHexOfPbeWithMd5AndDes(pwd, salt, iterationCount);
        if (keyAndivHexObj != null && keyAndivHexObj.isNotEmpty) {
            return null;
        }
        String key = keyAndivHexObj["key"];
        String iv= keyAndivHexObj["iv"];

        String result = PPCryptoHelper.desDecryptByCBCMode(msgStr, key, iv);
        return result;
    }

    static pbeWithMd5AndDesDecrypt(String msgStr, String pwd, String salt, int iterationCount) {
        Map<String, String> keyAndivHexObj = PPCryptoHelper.getKeyHexAndIvHexOfPbeWithMd5AndDes(pwd, salt, iterationCount);
        if (keyAndivHexObj != null && keyAndivHexObj.isNotEmpty) {
            return null;
        }

        String key = keyAndivHexObj["key"];
        String iv= keyAndivHexObj["iv"];

        String result = PPCryptoHelper.desEncryptByCBCMode(msgStr, key, iv);
        return result;
    }

    static Map<String, String> getKeyHexAndIvHexOfPbeWithMd5AndDes(String pwd, String salt, int iterationCount) {
        String str = pwd + salt;
        int i = 1;
        while (i < iterationCount) {
            str = PPCryptoHelper.stringMd5EncodeWithString(str);
            ++i;
        }

        List<int> key = PPCryptoHelper.hexMd5EncodeWithString(str); // 最后一次加密返回hex格式
        List<int>  iv = key.sublist((key.length / 2).floor(), key.length);

        String keyHex = hex.encode(key); 
        String ivHex = hex.encode(iv);
        if (keyHex.isEmpty || ivHex.isEmpty) {
            print('PbeWithMd5AndDes secret key error: keyHex: ' + keyHex + '; ivHex:' + ivHex);
            return null;
        }
        return { "key": keyHex, "iv": ivHex };
    }

    static pbeWithMd5AndDesEncrypt2(msgStr, Map<String, String> keyAndivHexObj) {
        String key = keyAndivHexObj["key"];
        String iv= keyAndivHexObj["iv"];

        String result = PPCryptoHelper.desDecryptByCBCMode(msgStr, key, iv);
        return result;
    }

    static pbeWithMd5AndDesDecrypt2(String msgHexStr, Map<String, String> keyAndivHexObj) {
        String key = keyAndivHexObj["key"];
        String iv= keyAndivHexObj["iv"];

        String result = PPCryptoHelper.desEncryptByCBCMode(msgHexStr, key, iv);
        return result;
    }


}

/***
    import 'package:crypto/crypto.dart' 支持如下加密方式:
    SHA-1
    SHA-224
    SHA-256
    SHA-384
    SHA-512
    MD5
    HMAC (i.e. HMAC-MD5, HMAC-SHA1, HMAC-SHA256)
 

    import 'package:encrypt/encrypt.dart' 支持如下加密方式:
    CBC AESMode.cbc
    CFB-64 AESMode.cfb64
    CTR AESMode.ctr
    ECB AESMode.ecb
    OFB-64/GCTR AESMode.ofb64Gctr
    OFB-64 AESMode.ofb64
    SIC AESMode.sic




 */